package de.fhd.pms.dao;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import de.fhd.pms.dto.FahrtAutoKundeDTO;
import de.fhd.pms.dto.FahrtDTO;
import de.fhd.pms.dto.FahrtKundenDTO;
import de.fhd.pms.model.Auto;
import de.fhd.pms.model.Fahrt;
import de.fhd.pms.model.Kunde;
import de.fhd.pms.model.Station;

/**
 * The Data access class for {@link Fahrt} objects. DAO encapsulates all
 * accesses to the data source, including construction and dismantling of the
 * connection. All Interaction with the database regarding the entity bean
 * {@link Fahrt} should be handled by this class! Its tasks:
 * <ul>
 * <li>set new objects of the class</li>
 * <li>modify or delete an object of the class</li>
 * <li>deliver all objects of the class</li>
 * <li>further functions in context to the class objects</li>
 * </ul>
 * 
 * @author Fischer, Neetzel & Six
 */

public class FahrtDao extends HibernateDaoSupport {
	SimpleDateFormat deutschesDatumsFormat = new SimpleDateFormat(
			"dd.MM.yyyy hh:mm");

	// neue Methode, Alex
	public Fahrt save(Fahrt fahrt) {
		HibernateTemplate template = getHibernateTemplate();

		template.saveOrUpdate(fahrt);
		return fahrt;
	}

	/**
	 * <p>
	 * returns all Fahrt objects, which are not yet termiated, i.e. which have a
	 * ankunft property == null. All the results are returned as FahrtKundenDTO
	 * objects.
	 * </p>
	 * <p>
	 * In order to access lazy loaded properties, a HibernateCallback is used.
	 * </p>
	 * 
	 * @return A sorted set of FahrtKundenDTO objects
	 * @see http 
	 *      ://static.springframework.org/spring/docs/2.5.x/reference/orm.html
	 *      #orm-hibernate-template
	 */
	// ORIGINAL
	// @SuppressWarnings({ "unchecked", "rawtypes" })
	// public Set<FahrtKundenDTO> findNichtBeendetDTO() {
	// HibernateTemplate template = getHibernateTemplate();
	// return (Set<FahrtKundenDTO>) template.execute(new HibernateCallback() {
	// @Override
	// public Object doInHibernate(Session session)
	// throws HibernateException, SQLException {
	// Criteria criteria = session.createCriteria(Fahrt.class);
	// criteria.add(Restrictions.isNull("ankunft"));
	// List<Fahrt> alleFahrten = criteria.list();
	// return createDtoSet(alleFahrten);
	// }
	// });
	// }
	
	//Unseres
	 @SuppressWarnings({ "unchecked", "rawtypes" })
	 public Set<FahrtDTO> findNichtBeendetDTO() {
	 HibernateTemplate template = getHibernateTemplate();
	 return (Set<FahrtDTO>) template.execute(new HibernateCallback() {
	 @Override
	 public Object doInHibernate(Session session)
	 throws HibernateException, SQLException {
	 Criteria criteria = session.createCriteria(Fahrt.class);
	 criteria.add(Restrictions.isNull("ankunft"));
	 List<Fahrt> alleFahrten = criteria.list();
	 return createDtoSet(alleFahrten);
	 }
	 });
	 }

	/**
	 * <p>
	 * returns all Fahrt objects as FahrtKundenDTO objects.
	 * </p>
	 * <p>
	 * In order to access lazy loaded properties of those, a HibernateCallback
	 * is used.
	 * </p>
	 * 
	 * @return A sorted set of FahrtKundenDTO objects
	 * @see http 
	 *      ://static.springframework.org/spring/docs/2.5.x/reference/orm.html
	 *      #orm-hibernate-template
	 */
	// ORIGINAL
	// @SuppressWarnings({ "unchecked", "rawtypes" })
	// public Set<FahrtKundenDTO> findAllDTO() {
	// HibernateTemplate template = getHibernateTemplate();
	// return (Set<FahrtKundenDTO>) template.execute(new HibernateCallback() {
	// @Override
	// public Object doInHibernate(Session session)
	// throws HibernateException, SQLException {
	// Criteria criteria = session.createCriteria(Fahrt.class);
	// List<Fahrt> alleFahrten = criteria.list();
	// return createDtoSet(alleFahrten);
	// }
	// });
	// }
	 
		public Fahrt findById(int id) {
			HibernateTemplate template = getHibernateTemplate();
			return (Fahrt) template.get(Fahrt.class, id);
		}

	// Unseres
//	@SuppressWarnings({ "unchecked", "rawtypes" })
//	public Set<FahrtDTO> findAllDTO() {
//		HibernateTemplate template = getHibernateTemplate();
//		return (Set<FahrtDTO>) template.execute(new HibernateCallback() {
//			@Override
//			public Object doInHibernate(Session session)
//					throws HibernateException, SQLException {
//				Criteria criteria = session.createCriteria(Fahrt.class);
//				List<Fahrt> alleFahrten = criteria.list();
//				return createDtoSet(alleFahrten);
//			}
//		});
//	}
//	
	
	 @SuppressWarnings({ "unchecked", "rawtypes" })
	 public Set<FahrtDTO> findAllDTO() {
	 HibernateTemplate template = getHibernateTemplate();
	 return (Set<FahrtDTO>) template.execute(new HibernateCallback() {
	 @Override
	 public Object doInHibernate(Session session)
	 throws HibernateException, SQLException {
	 Criteria criteria = session.createCriteria(Fahrt.class);
	 criteria.add(Restrictions.isNotNull("ankunft"));
	 List<Fahrt> alleFahrten = criteria.list();
	 return createDtoSet(alleFahrten);
	 }
	 });
	 }

	/**
	 * Private utility function
	 * 
	 * @param fahrten
	 *            a List of persistent Fahrt objects
	 * @return a Set of FahrtKundenDTO objects
	 */
	// ORIGINAL
	// private Set<FahrtKundenDTO> createDtoSet(List<Fahrt> fahrten) {
	// Set<FahrtKundenDTO> results = new TreeSet<FahrtKundenDTO>();
	// for (Fahrt f : fahrten) {
	// Date a = f.getAnkunft();
	// results.add(new FahrtKundenDTO(f.getAbfahrt(), f.getId(), f
	// .getAuto().getMarke(), deutschesDatumsFormat.format(f
	// .getAbfahrt()), (a == null ? "" : deutschesDatumsFormat
	// .format(a)), mannschaftToString(f.getRuderer())));
	// }
	// return results;
	// }

	// Unsere
	private Set<FahrtDTO> createDtoSet(List<Fahrt> fahrten) {
		Set<FahrtDTO> results = new TreeSet<FahrtDTO>();
		for (Fahrt f : fahrten) {
			f.getAnkunft();
			results.add(new FahrtDTO(f.getId(), f.getAuto().getMarke(), f
					.getKunde().getVorname(), f.getKm(), f.getAbfahrt(), f
					.getAnkunft(), f.getDauer(), f.getKosten()));
		}
		return results;
	}

	/**
	 * Private utility function
	 * 
	 * @param rudererSet
	 *            a Set of Kunde objects
	 * @return a String of the names of those Kunde objects
	 */
	// ORIGINAL
	// private String mannschaftToString(Set<Kunde> rudererSet) {
	// String mannschaft = "";
	// String trenner = "";
	// for (Kunde ruderer : rudererSet) {
	// mannschaft = mannschaft + trenner + ruderer.getVorname() + " "
	// + ruderer.getNachname();
	// trenner = ", ";
	// }
	// return mannschaft;
	// }

	/**
	 * Returns all {@link Fahrt} objects from the DB
	 * 
	 * @return a list of {@link Fahrt} objects
	 * @see Fahrt
	 */
	@SuppressWarnings("unchecked")
	public List<Fahrt> findAll() {
		HibernateTemplate template = getHibernateTemplate();
		@SuppressWarnings("rawtypes")
		List alleFahrten = template.loadAll(Fahrt.class);
		
		return (List<Fahrt>) alleFahrten;
	}

	/**
	 * Starts a trip specifying a Auto id and a set of Kunde ids.
	 * 
	 * @param autoId
	 * @param sitz
	 */

	
//	 Methode um eine Fahrt zu beginnen.
//	 Es werden die Fremdschlüssel von Auto und Kunde übergeben
//	 Das Feld Station wird null gesetzt um zu erkennen, dass dieses Auto zur Zeit ausgeliehen ist 
	public void beginne(int autoId, int kundeId) {
		HibernateTemplate template = getHibernateTemplate();
		Auto auto = (Auto) template.get(Auto.class, autoId);
		Kunde kunde = (Kunde) template.get(Kunde.class, kundeId);
		Fahrt f = new Fahrt();
		auto.setStation(null);
		f.setAuto(auto);
		f.setKunde(kunde);
		template.saveOrUpdate(f);
		template.saveOrUpdate(auto);
	}

	// ORIGINAL
	// public void beginne(int autoId, Integer[] sitz) {
	// HibernateTemplate template = getHibernateTemplate();
	// Auto a = (Auto) template.get(Auto.class, autoId);
	// Set<Kunde> ruderer = new HashSet<Kunde>();
	// for(Integer kundeId : sitz) {
	// ruderer.add((Kunde) template.get(Kunde.class, kundeId));
	// }
	// Fahrt f = new Fahrt();
	// f.setAuto(b);
	// f.setRuderer(ruderer);
	// template.saveOrUpdate(f);
	// }

	/**
	 * Ends a trip by adding an ankunft date.
	 * 
	 * @param id
	 */
	public void beende(int fId, int sId, float km) {
		HibernateTemplate template = getHibernateTemplate();
		Fahrt f = (Fahrt) template.get(Fahrt.class, fId);
		Auto a = (Auto) template.get(Auto.class, f.getAuto().getId()); 
		Station s = (Station) template.get(Station.class, sId); //TODO 3 ist nur ein test
		f.setAnkunft(new Date());
		a.setStation(s);
		f.setDauer(f.getAbfahrt(), f.getAnkunft()); 
		f.getDauer();
		f.setKm(km);
		f.setKosten(f.getDauer(),f.getKm());
		a.setKm(a.getKm()+km);
		template.saveOrUpdate(f);
		template.saveOrUpdate(a);
	}

	/**
	 * <p>
	 * returns all Fahrt objects as FahrtAutoKundeDTO objects.
	 * </p>
	 * <p>
	 * In order to access lazy loaded properties of those, a HibernateCallback
	 * is used.
	 * </p>
	 * 
	 * @return A sorted set of FahrtKundenDTO objects
	 * @see http 
	 *      ://static.springframework.org/spring/docs/2.5.x/reference/orm.html
	 *      #orm-hibernate-template
	 */
	// ORIGINAL
	// @SuppressWarnings({ "unchecked", "rawtypes" })
	// public List<FahrtAutoKundeDTO> findAllVoll() {
	// HibernateTemplate template = getHibernateTemplate();
	// return (List<FahrtAutoKundeDTO>) template
	// .execute(new HibernateCallback() {
	// @Override
	// public Object doInHibernate(Session session)
	// throws HibernateException, SQLException {
	// Criteria criteria = session.createCriteria(Fahrt.class);
	// List<Fahrt> alleFahrten = criteria.list();
	// List<FahrtAutoKundeDTO> liste = new LinkedList<FahrtAutoKundeDTO>();
	// for (Fahrt f : alleFahrten) {
	// Set<Kunde> ruderer = f.getRuderer();
	// for (Kunde p : ruderer) {
	// FahrtAutoKundeDTO fbpDto = new FahrtAutoKundeDTO(
	// f, p);
	// liste.add(fbpDto);
	// }
	// }
	// return liste;
	// }
	// });
	// }

	/**
	 * 
	 * @param auto
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Set<Fahrt> findByAuto(Auto auto) {
		Session hibernateSession = getSession();
		Criteria crit = hibernateSession.createCriteria(Fahrt.class);
		crit.add(Restrictions.eq("auto", auto));
		List<Fahrt> tmp = crit.list();
		Set<Fahrt> result = new HashSet<Fahrt>();
		for (Fahrt f : tmp) {
			result.add(f);
		}
		return result;
	}

	// neue Methode für KundeDeleteException! Phil
	@SuppressWarnings("unchecked")
	public Set<Fahrt> findByKunde(Kunde kunde) {
		Session hibernateSession = getSession();
		Criteria crit = hibernateSession.createCriteria(Fahrt.class);
		crit.add(Restrictions.eq("kunde", kunde));
		List<Fahrt> tmp = crit.list();
		Set<Fahrt> result = new HashSet<Fahrt>();
		for (Fahrt f : tmp) {
			result.add(f);
		}
		return result;
	}

}
